﻿using System;
using System.Linq;
using CID.Domain.Development;
using CID.Domain.Infrastructure;
using CID.Domain.Operations;
using CID.Execution.Agent.Tests.Support;
using CID.Execution.Support.Information;
using CID.Execution.Support.PackageHandling;
using CID.Execution.Support.Scripting;
using CID.Execution.Support.TemplateHandling;
using NUnit.Framework;
using Rhino.Mocks;

namespace CID.Execution.Agent.Tests
{
    [TestFixture]
    class DeploymentScriptExecuterTests : BaseAgentTests
    {
        private const string CustomParameterName = "The Parameter Name";
        private const string CustomParameterValue = "SomeValue";

        private DeploymentScriptExecuter scriptExecuter;
        private LocationDeploymentScript script;
        private DeploymentScriptStep scriptStep;

        public override void SetUp()
        {
            base.SetUp();

            var location = GenerateNamedEntityStub<ILocation>();
            var release = GenerateNamedEntityStub<IRelease>();
            var component = GenerateNamedEntityStub<IComponent>();
            var version = GenerateNamedEntityStub<IVersion>();
            version.Stub(x => x.Component).Return(component);
            var templateType = GenerateNamedEntityStub<ITemplateType>();
            var template = GenerateNamedEntityStub<ITemplate>();
            template.Stub(x => x.Type).Return(templateType);
            var packageType = GenerateNamedEntityStub<IPackageType>();
            var package = MockRepository.GenerateStub<IPackage>();
            package.Stub(x => x.Content).Return(new byte[] { 1, 2, 3 });
            package.Stub(x => x.Version).Return(version);
            package.Stub(x => x.Type).Return(packageType);

            scriptStep = new DeploymentScriptStep();
            scriptStep.Version = new VersionInfo(version);
            scriptStep.Template = new TemplateInfo(template);
            scriptStep.Package = new PackageInfo(package);
            scriptStep.ParameterValues = new ParameterValueInfo[] { ParameterValueInfo.CreateAdditionalParameterValue(CustomParameterName, CustomParameterValue) };
            script = new LocationDeploymentScript(Guid.NewGuid(), release, location, new DeploymentScriptStep[] { scriptStep });
            scriptExecuter = new DeploymentScriptExecuter(script);

            ControllerServiceProxyStub.ClearFlags();
            TemplateHandlerStub.ClearLists();
            PackageHandlerStub.ClearFlags();
            TemplateHandlerFactory.Instance.RegisterTemplateHandlerType(scriptStep.Template.Type.Name, typeof(TemplateHandlerStub));
            PackageHandlerFactory.Instance.RegisterPackageHandlerType(scriptStep.Package.Type.Name, typeof(PackageHandlerStub));
        }

        public override void TearDown()
        {
            TemplateHandlerFactory.Instance.UnregisterTemplateHandlerType(scriptStep.Template.Type.Name);
            PackageHandlerFactory.Instance.UnregisterPackageHandlerType(scriptStep.Package.Type.Name);
            base.TearDown();
        }

        #region ExecuteStep
        [Test]
        public void ExecuteStep_CustomTemplateHandlerRegistered_ShouldEndSuccessfully()
        {
            scriptExecuter.Execute();

            CollectionAssert.AreEquivalent(scriptStep.ParameterValues, TemplateHandlerStub.ParameterValues);
            CollectionAssert.AreEquivalent(
                new String[] { Parameter.ReservedNames.ReleaseName, Parameter.ReservedNames.ComponentName, Parameter.ReservedNames.VersionName, Parameter.ReservedNames.PackageComment, Parameter.ReservedNames.PackagePath }, 
                TemplateHandlerStub.AdditionalParameterValues.Select(x => x.ParameterName));
            Assert.IsTrue(PackageHandlerStub.PrepareForUsageCalled);
            Assert.IsTrue(PackageHandlerStub.ReleaseCalled);
            Assert.IsTrue(ControllerServiceProxyStub.NotifyDeploymentCompletedCalled);
            Assert.IsFalse(ControllerServiceProxyStub.NotifyDeploymentCompletedWithErrors);
            Assert.IsFalse(ControllerServiceProxyStub.NotifyActivationCompletedCalled);
            Assert.IsFalse(ControllerServiceProxyStub.NotifyDeactivationCompletedCalled);
        }

        [Test]
        public void ExecuteStep_CustomTemplateHandlerNotRegistered_ShouldEndWithErrors()
        {
            TemplateHandlerFactory.Instance.UnregisterTemplateHandlerType(scriptStep.Template.Type.Name);

            scriptExecuter.Execute();

            Assert.IsTrue(PackageHandlerStub.PrepareForUsageCalled);
            Assert.IsTrue(PackageHandlerStub.ReleaseCalled);
            Assert.IsTrue(ControllerServiceProxyStub.NotifyDeploymentCompletedCalled);
            Assert.IsTrue(ControllerServiceProxyStub.NotifyDeploymentCompletedWithErrors);
            Assert.IsFalse(ControllerServiceProxyStub.NotifyActivationCompletedCalled);
            Assert.IsFalse(ControllerServiceProxyStub.NotifyDeactivationCompletedCalled);
        }

        [Test]
        public void ExecuteStep_CustomPackageHandlerNotRegistered_ShouldEndWithErrors()
        {
            PackageHandlerFactory.Instance.UnregisterPackageHandlerType(scriptStep.Package.Type.Name);

            scriptExecuter.Execute();

            Assert.IsFalse(PackageHandlerStub.PrepareForUsageCalled);
            Assert.IsFalse(PackageHandlerStub.ReleaseCalled);
            CollectionAssert.IsEmpty(TemplateHandlerStub.ParameterValues);
            CollectionAssert.IsEmpty(TemplateHandlerStub.AdditionalParameterValues);
            Assert.IsTrue(ControllerServiceProxyStub.NotifyDeploymentCompletedCalled);
            Assert.IsTrue(ControllerServiceProxyStub.NotifyDeploymentCompletedWithErrors);
            Assert.IsFalse(ControllerServiceProxyStub.NotifyActivationCompletedCalled);
            Assert.IsFalse(ControllerServiceProxyStub.NotifyDeactivationCompletedCalled);
        }
        #endregion

        #region OnExecutionEnded
        [Test]
        public void FailCallToController_ShouldSucceedAndLog()
        {
            ControllerServiceProxyStub.FailOnCall = true;

            scriptExecuter.Execute();

            Assert.IsFalse(ControllerServiceProxyStub.NotifyDeploymentCompletedCalled);
        }
        #endregion
    }
}
